//
// Created by QU on 2024/1/18.
//

// c++ standard library
#include <cassert>
#include <iostream>
#include <list>
#include <vector>
#include <map>
#include <set>

// boost library
#include <boost/pool/pool.hpp>
#include <boost/pool/object_pool.hpp>

// using namespace
using std::cin, std::cout, std::endl;
using std::string;
using boost::pool;
using boost::object_pool;

// pool包含4个组成部分: 最简单的pool;  分配类实例的object_pool; 单间内存池singleton_pool; 可用于标准库的pool_alloc. (只介绍前3个)

struct demo_class {
public:
    int a,b,c,x;

    // constructor
    demo_class(int a =1, int b = 2, int c = 3) : a(a), b(b), c(c){}
};

int main(int argc, char const *argv[]){
    // boost.pool只能使用于标准类型(通用类型), 不能将他用在复杂的类或者对象中, 因为他不会主动调用类的析构函数.
    // 如果想要主动调用析构函数, 请使用object_pool.

    // object_pool是pool类的子类, 但他使用的是保护的继承类, 因此不能使用pool的接口, 但是他们的基本功能还是非常类似的.
    // object_pool的模本类型参数T指定了object_pool要分配的元素类型, 要求存储的对象的析构函数不能抛出异常.

    // malloc函数和free分配和释放一个类型为T*的内存块, is_from()可以测试内存块的归属, 但是这将会将块直接映射, 除了开辟空间不进行任何操作,
    // 他们被调用的时候不调用类的构造函数或者析构函数, 操作的是原始的内存块, 里边的值是未定义的, 所以尽量减少使用malloc和free在obj_pool上.

    // object_pool的特殊的地方在于 construct()和 destroy()函数

    // construct()是一组函数, 有多个参数, 他先调用malloc()函数分配内存,
    // 然后再内存块上使用传入的参数调用类的构造函数, 返回一个已经初始化的对象指针.
    // destroy()相反, 先调用析构函数, 然后调用free().

    // 如果分配失败将返回0.

    object_pool<demo_class> p1;

    cout << "Next size is: " << p1.get_next_size() << endl;
    auto p = p1.malloc();
    assert(p1.is_from(p));
    cout << "Next size is: " << p1.get_next_size() << endl;
    assert(p->a != 1 || p->b != 2 || p->c != 3);    // not invoke constructor.

    p1.construct(7,8,9);

    object_pool<std::string> ojpl_string;
    cout << "object_pool Next size is: " << ojpl_string.get_next_size() << endl;
    for (int i = 0; i < 1000; ++i) {
        string *ps = ojpl_string.construct("hello object pool!");
        // 因为malloc的时候不会返回异常. 所以实际编写代码的时候都需要检查malloc返回的指针.  虽然说这种情况比较少出现.
        if (!ps){
            cout  << "pool Memory malloc error." << endl;
            break;
        }
        cout << i <<": "<< *ps << endl;
        cout << "object_pool Next size is: " << ojpl_string.get_next_size() << endl;
    }

    // 默认情况下, boost为我们提供了3个参数, 但是有些时候是不够用的, 这个时候construct()函数的默认形式就不好用了.
    // pool库在<boost/pool/detail/下提供了两个名为pool_construct.m4和pool_construct_simple的脚本, \
    // 同时提供了在UNIX和Windows的sh和bat的脚本, 向这个脚本中传入一个N, 他就能生成带有N个参数的constructor().

    // 当然使用m4的方式比较笨拙, 现代的c++已经有解决方案.
    // 你可以使用c++11中的可变模板参数特性, 我们可以定义一个辅助模板函数, 支持任意个数量的参数, 解决相关的问题.
    // 在下面.

/*
    struct aquawius_demo{
        int a,b,c,d;
    public:
        aquawius_demo(int a, int b, int c,int d) : a(a), b(b), c(c), d(d) {}
    };

    object_pool<aquawius_demo> ojpl_aquawius;
    ojpl_aquawius.construct(ojpl_aquawius, 1,2,3,4);
*/


}

// 第一个是object_pool, 然后是需要创建对象的参数, 要创建的对象类型可以通过object_pool的内部类型宏element_type获得
// 这个函数先调用了malloc()分配一块内存, 然后利用了c++中不太常见的定位new表达式(placement new expression)来创建对象.
template <typename P, typename ... Args>    // 可变参数模板
inline typename P::element_type * construct(P& p, Args&& ...args){
    typename P::element_type * mem = p.malloc();

    assert(mem != 0);
    new (mem) typename P::element_type (std::forward<Args>(args) ...);          // 完美转发
    return mem;
}

